#pragma once

#include "CharReader2.hpp"

class Tokenizer2
{
public:
	enum TOKEN_TYPE
	{
		TOKEN_EOF,
		TOKEN_SYMBOL,
		TOKEN_IDENTIFIER,
		TOKEN_INTEGER,
		TOKEN_FLOAT,
		TOKEN_STRING,
		TOKEN_CHAR,
		TOKEN_COUNT
	};
	static const char * TOKEN_TYPE_NAMES[];

	struct Iterator
	{
		CharReader2::Iterator CharReaderIt;
		TOKEN_TYPE Type;
		string Str;

		Iterator(const CharReader2::Iterator &charReaderIt, TOKEN_TYPE type, const string &str) : CharReaderIt(charReaderIt), Type(type), Str(str) { }
	};

	Tokenizer2(CharReader2 &cr);

	TOKEN_TYPE GetType() { return m_Type; }
	const tstring & GetString() { return m_Str; }
	void Next();

	bool QueryToken(TOKEN_TYPE type) { return m_Type == type; }
	bool QueryToken(TOKEN_TYPE type1, TOKEN_TYPE type2) { return m_Type == type1 || m_Type == type2; }
	bool QuerySymbol(char ch) { return m_Str.length() == 1 && m_Str[0] == ch; }
	bool QuerySymbol(const string &s) { return m_Str == s; }
	bool QueryIdentifier(const string &s) { return m_Str == s; }

	void AssertToken(TOKEN_TYPE type);
	void AssertToken(TOKEN_TYPE type1, TOKEN_TYPE type2);
	void AssertSymbol(char ch);
	void AssertIdentifier(const string &s);
	void AssertEOF() { AssertToken(TOKEN_EOF); }
	void CreateError();
	void CreateError(const string &msg);

	Iterator GetIterator() { return Iterator(m_cr.GetIterator(), m_Type, m_Str); }
	void SetIterator(const Iterator &it) { m_cr.SetIterator(it.CharReaderIt); m_Type = it.Type; m_Str = it.Str; }

private:
	CharReader2 &m_cr;
	TOKEN_TYPE m_Type;
	string m_Str;

	void SkipWhitespace();
	char ParseStringChar();
};
